{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sistemas de Recomendação\n",
    "\n",
    "A ideia aqui é bem simples: implementarmos um Sistema de Recomendação que vai recomendar áreas de estudo da computação para usuários. O nosso Sistema de Recomendação se baseará nos interesses dos outros usuários para efetuar a recomendação."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import exercise_utils as eu\n",
    "import math\n",
    "from collections import defaultdict\n",
    "\n",
    "# esse é o nosso dataset\n",
    "users_interests = eu.get_users_interests() # se não tivermos o dataset, usar eu.get_users_interests_poor()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "O código abaixo cria um vetor global de todos os possíveis interesses. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "unique_interests = sorted(list({ interest \n",
    "                                for user_interests in users_interests\n",
    "                                for interest in user_interests }))\n",
    "unique_interests"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Montando a Matrix\n",
    "\n",
    "Implemente a função __make_user_interest_vector__ abaixo. Ela será usada para montar a matrix de interesse."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "def make_user_interest_vector(user_interests):\n",
    "    \"\"\" Essa função recebe uma lista de interesses de um usuário e \n",
    "        retorna a lista unique_interests substituindo o interesses \n",
    "        por 0 ou 1 seguindo a lógica: \n",
    "            1, se o item de unique_interests está na user_interest.\n",
    "            0, se o item de unique_interests NÃO está na user_interest \"\"\"\n",
    "    return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "user_interest_matrix = map(make_user_interest_vector, users_interests)\n",
    "\n",
    "# A user é formada dos seguintes dados:\n",
    "#   - cada LINHA representa o interesse de um usuário para todos os interesses\n",
    "#   - cada COLUNA é o índice global de um interesse\n",
    "#   - cada CÉLULA(u, i) contém 1 ou 0: 1 se o usuário u se interessa em i, 0 caso contrário\n",
    "eu.print_matrix(user_interest_matrix)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Função de Similaridade\n",
    "\n",
    "Implemente a função de [similaridade cosseno](https://en.wikipedia.org/wiki/Cosine_similarity#Definition). Essa função retorna valores entre 0 e 1. Quanto mais próximo de 1, mais semelhantes são os vetores. Quanto mais próximo de 0, mais diferentes eles são."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def cosine_similarity(va, vb):\n",
    "    return 0.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Usando a função de similaridade implementada, o código abaixo cria uma outra matriz. Essa nova matriz é NxN, onde N é o número de usuários. Cada célula _(i, j)_ contém a similaridade do vetor de interesse do usuário _i_ com o vetor de interesse do usuário _j_."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "user_similarities = [[cosine_similarity(user_i_interest_vector, user_j_interest_vector) \n",
    "                      for user_j_interest_vector in user_interest_matrix] \n",
    "                     for user_i_interest_vector in user_interest_matrix]\n",
    "\n",
    "eu.print_matrix(user_similarities)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Algoritmo de Recomendação"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A primeira etapa da implementação do nosso algoritmo envolve essa função auxiliar, definida abaixo. Ela deve ser implementada de acordo com a implementação do algoritmo abaixo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# ALGORITMO: most_similar_users_to\n",
    "# ENTRADA: usuario_id: identificador de um usuário. O índice do usuário na matriz dos dados.\n",
    "# SAÍDA: Lista de 2-tuplas contendo ( outro usuário != user_id, similaridade entre o usuário e user_id).\n",
    "#        A lista retornada deve ser ordenada pela similaridade entre os usuários.\n",
    "#\n",
    "# BEGIN\n",
    "# \n",
    "# pares <- []\n",
    "#\n",
    "# FOR EACH outro_usuario_id, similaridade IN enumerate(user_similarities) THEN:\n",
    "#   IF outro_usuario_id != user_id AND similaridade > 0 THEN:\n",
    "#     pares.add((outro_usuario_id, similaridade))\n",
    "#\n",
    "# RETURN ordenar(pares, por=similaridade, em_ordem=decrescente)\n",
    "# \n",
    "# END\n",
    "\n",
    "def most_similar_users_to(user_id):\n",
    "    return []"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Implementada a função que obtém os usuários mais similares a um dado usuário, a segunda etapa do nosso algoritmo pode usá-la para obter uma lista de recomendações de interesses para um dado usuário. Basta implementar a função a seguir de acordo com a descrição dada:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# ALGORITMO: user_based_suggestions\n",
    "# ENTRADA: usuario_id: identificador de um usuário. O índice do usuário na matriz dos dados.\n",
    "# SAÍDA: Uma lista de interesses não \"marcados\" pelo usuário ordenada pelo índice de recomendação do algoritmo.\n",
    "#\n",
    "# BEGIN\n",
    "#\n",
    "# // Somando as similaridades de cada interesse em um dicionário. A chave é o interesse e o valor o peso.\n",
    "# sugestoes <- empty_float_dict()\n",
    "# FOR EACH outro_usuario_id, similaridade IN most_similar_users_to(usuario_id) THEN:\n",
    "#   FOR EACH interesse IN users_interests[outro_usuario_id] THEN:\n",
    "#     sugestoes[intersse] += similaridade\n",
    "#\n",
    "# // convertendo dicionário para um lista ordenada\n",
    "# sugestoes = ordernar(sugestoes.items(), por=peso, em_order=decrescente)\n",
    "#\n",
    "# sugestoes_final = []\n",
    "# FOR EACH sugestao IN sugestoes THEN:\n",
    "#   IF sugestao NOT IN users_interests[user_id] THEN:\n",
    "#     suggestoes_final.add(sugestao)\n",
    "# END\n",
    "\n",
    "def user_based_suggestions(user_id):\n",
    "    return []"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Para vermos o resultado da recomendação, basta chamar a função __user_based_suggestions__ informado o identificador do usuário:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "user_based_suggestions(0)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
